<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>AI 流式聊天界面</title>
    <style>
        /* 简单样式：美观且清晰 */
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: "Microsoft YaHei", sans-serif;
        }
        .chat-container {
            max-width: 800px;
            margin: 20px auto;
            border: 1px solid #e5e7eb;
            border-radius: 8px;
            overflow: hidden;
            box-shadow: 0 2px 10px rgba(0,0,0,0.05);
        }
        .chat-header {
            background-color: #2563eb;
            color: white;
            padding: 16px;
            font-size: 18px;
            font-weight: 600;
        }
        .chat-messages {
            height: 500px;
            padding: 20px;
            overflow-y: auto; /* 滚动显示历史消息 */
            background-color: #f9fafb;
        }
        /* 消息气泡样式：区分用户和AI */
        .message {
            margin-bottom: 16px;
            padding: 12px 16px;
            border-radius: 8px;
            max-width: 70%;
            line-height: 1.5;
        }
        .user-message {
            background-color: #2563eb;
            color: white;
            margin-left: auto; /* 用户消息右对齐 */
        }
        .ai-message {
            background-color: white;
            color: #111827;
            border: 1px solid #e5e7eb;
            margin-right: auto; /* AI消息左对齐 */
        }
        .loading {
            color: #6b7280;
            font-style: italic;
            margin-bottom: 16px;
        }
        .chat-input {
            display: flex;
            padding: 16px;
            background-color: white;
            border-top: 1px solid #e5e7eb;
        }
        #message-input {
            flex: 1;
            padding: 12px 16px;
            border: 1px solid #e5e7eb;
            border-radius: 6px;
            font-size: 14px;
            outline: none;
        }
        #message-input:focus {
            border-color: #2563eb;
        }
        #send-btn {
            margin-left: 12px;
            padding: 12px 24px;
            background-color: #2563eb;
            color: white;
            border: none;
            border-radius: 6px;
            font-size: 14px;
            font-weight: 500;
            cursor: pointer;
        }
        #send-btn:hover {
            background-color: #1d4ed8;
        }
    </style>
</head>
<body>
<div class="chat-container">
    <!-- 聊天头部 -->
    <div class="chat-header">AI 流式聊天（基于 Ollama + Spring Boot）</div>

    <!-- 聊天消息区 -->
    <div class="chat-messages" id="chat-messages"></div>

    <!-- 输入区 -->
    <div class="chat-input">
        <input type="text" id="message-input" placeholder="请输入消息...">
        <button id="send-btn">发送</button>
    </div>
</div>

<script>
    // DOM 元素获取（不变）
    const chatMessages = document.getElementById('chat-messages');
    const messageInput = document.getElementById('message-input');
    const sendBtn = document.getElementById('send-btn');

    // 新增：重连限制+片段合并变量
    let reconnectCount = 0; // 重连次数计数器
    let fragmentBuffer = []; // 短片段缓冲区
    let fragmentTimer = null; // 合并定时器

    // 1. 发送消息逻辑（优化版）
    function sendMessage() {
        const userInput = messageInput.value.trim();
        if (!userInput) return;

        // 清空之前的缓冲区和定时器（避免新消息与旧片段混淆）
        clearFragmentBuffer();

        addMessageToUI('user', userInput);
        messageInput.value = '';
        reconnectCount = 0; // 重置重连次数

        // 关闭旧连接（不变）
        if (window.eventSource) {
            window.eventSource.close();
        }

        const loadingId = addLoadingToUI();
        const encodedInput = encodeURIComponent(userInput);

        // 建立新连接（添加重连限制）
        window.eventSource = new EventSource(`/ai/chat/stream/${encodedInput}`);

        // 2. 接收流式消息（优化：合并短片段）
        window.eventSource.onmessage = function(event) {
            if (document.getElementById(loadingId)) {
                document.getElementById(loadingId).remove();
            }
            // 将短片段加入缓冲区，定时合并
            addToFragmentBuffer('ai', event.data);
        };

        // 3. 错误处理（优化：限制重连+主动关闭）
        window.eventSource.onerror = function(error) {
            document.getElementById(loadingId).remove();
            reconnectCount++;
            // 重连超过 3 次则停止，避免无限请求
            if (reconnectCount > 3) {
                addMessageToUI('ai', '请求失败，已停止重试，请刷新页面重试');
                window.eventSource.close();
                return;
            }
            addMessageToUI('ai', `出错了（第 ${reconnectCount} 次重试）：${error?.message || '未知错误'}`);
        };

        // 4. 连接关闭（优化：清空缓冲区）
        window.eventSource.onclose = function() {
            console.log('AI 消息生成完成');
            // 关闭前将剩余缓冲区内容显示（避免遗漏）
            flushFragmentBuffer();
        };
    }

    // 新增：短片段合并逻辑（50ms 合并一次，平衡实时性与显示效果）
    function addToFragmentBuffer(sender, content) {
        fragmentBuffer.push(content); // 加入缓冲区
        clearTimeout(fragmentTimer); // 重置定时器
        // 50ms 后合并并显示（可根据需求调整，如 30-100ms）
        fragmentTimer = setTimeout(() => {
            flushFragmentBuffer(sender);
        }, 50);
    }

    // 新增：清空缓冲区并显示合并后的内容
    function flushFragmentBuffer(sender) {
        if (fragmentBuffer.length === 0) return;
        // 合并所有片段，替换多余换行（解决“莫名换行”）
        const mergedContent = fragmentBuffer.join('').replace(/\n+/g, '\n'); // 多个\n转为一个
        addMessageToUI(sender, mergedContent);
        fragmentBuffer = []; // 清空缓冲区
    }

    // 新增：清空缓冲区和定时器
    function clearFragmentBuffer() {
        clearTimeout(fragmentTimer);
        fragmentBuffer = [];
    }

    // 2. 向界面添加消息（不变）
    function addMessageToUI(sender, content) {
        const messageDiv = document.createElement('div');
        messageDiv.className = `message ${sender}-message`;
        messageDiv.innerHTML = content.replace(/\n/g, '<br>'); // 正常换行转<br>
        chatMessages.appendChild(messageDiv);
        chatMessages.scrollTop = chatMessages.scrollHeight;
    }

    // 3. 添加 "AI正在输入" 提示（不变）
    function addLoadingToUI() {
        const loadingId = `loading-${Date.now()}`;
        const loadingDiv = document.createElement('div');
        loadingDiv.id = loadingId;
        loadingDiv.className = 'loading';
        loadingDiv.textContent = 'AI 正在思考...';
        chatMessages.appendChild(loadingDiv);
        chatMessages.scrollTop = chatMessages.scrollHeight;
        return loadingId;
    }

    // 4. 绑定事件（不变）
    sendBtn.addEventListener('click', sendMessage);
    messageInput.addEventListener('keypress', function(e) {
        if (e.key === 'Enter') sendMessage();
    });
</script>
</body>
</html>